////////////////////////////////////////////////////////////////////////////////
// Copyright 2010 Michael Schmalle - Teoti Graphix, LLC
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0 
// 
// Unless required by applicable law or agreed to in writing, software 
// distributed under the License is distributed on an "AS IS" BASIS, 
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and 
// limitations under the License
// 
// Author: Michael Schmalle, Principal Architect
// mschmalle at teotigraphix dot com
////////////////////////////////////////////////////////////////////////////////

package org.teotigraphix.swizplugin.registry.core
{

import flash.utils.getQualifiedClassName;

import mx.rpc.IResponder;

import org.teotigraphix.swizplugin.core.ExecutableRequest;
import org.teotigraphix.swizplugin.core.PluginOptions;
import org.teotigraphix.swizplugin.registry.IContributor;
import org.teotigraphix.swizplugin.registry.IExtension;
import org.teotigraphix.swizplugin.registry.IExtensionDescriptor;

/**
 * The concrete implementation of <code>IExtensionDescriptor</code>.
 * 
 * @author Michael Schmalle
 * @copyright Teoti Graphix, LLC
 * @productversion 1.0
 */
public class RegistryExtensionDescriptor 
	extends RegistryClient 
	implements IExtensionDescriptor
{
	//--------------------------------------------------------------------------
	//
	//  Internal :: Properties
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	//  contributorID
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _contributorID:int;
	
	/**
	 * Returns the contributing plugin id.
	 */
	internal function get contributorID():int
	{
		return _contributorID;
	}
	
	/**
	 * @private
	 */
	internal function set contributorID(value:int):void
	{
		_contributorID = value;
	}
	
	//----------------------------------
	//  parentID
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _parentID:int;
	
	/**
	 * Returns the parent's <code>registryID</code>.
	 * 
	 * <p>The parent can be an <code>IExtension</code> or 
	 * <code>IExtensionDescriptor</code>.</p>
	 */
	internal function get parentID():int
	{
		return _parentID;
	}
	
	/**
	 * @private
	 */
	internal function set parentID(value:int):void
	{
		_parentID = value;
	}
	
	//----------------------------------
	//  properties
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _properties:Object;
	
	/**
	 * Returns the attributes as an Object name - value pair.
	 */
	internal function get properties():Object
	{
		return _properties;
	}
	
	/**
	 * @private
	 */
	internal function set properties(value:Object):void
	{
		_properties = value;
	}
	
	//--------------------------------------------------------------------------
	//
	//  IExtensionDescriptor API :: Properties
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	//  contributor
	//----------------------------------
	
	/**
	 * @copy org.teotigraphix.swizplugin.registry.IExtensionDescriptor#contributor
	 */
	public function get contributor():IContributor
	{
		return registry.getContributor(contributorID);
	}
	
	//----------------------------------
	//  name
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _name:String;
	
	/**
	 * @copy org.teotigraphix.swizplugin.registry.IExtensionDescriptor#name
	 */
	public function get name():String
	{
		return _name;
	}
	
	/**
	 * @private
	 */
	public function set name(value:String):void
	{
		_name = value;
	}
	
	//----------------------------------
	//  uniqueID
	//----------------------------------
	
	/**
	 * @copy org.teotigraphix.swizplugin.registry.IExtensionDescriptor#uniqueID
	 */
	public function get uniqueID():String
	{
		return extension.uniqueID;
	}
	
	//----------------------------------
	//  namespaceID
	//----------------------------------
	
	/**
	 * @copy org.teotigraphix.swizplugin.registry.IExtensionDescriptor#namespaceID
	 */
	public function get namespaceID():String
	{
		return extension.namespaceID;
	}
	
	//----------------------------------
	//  internalID
	//----------------------------------
	
	/**
	 * @copy org.teotigraphix.swizplugin.registry.IExtensionDescriptor#internalID
	 */
	public function get internalID():int
	{
		return registryID;
	}
	
	//----------------------------------
	//  extension
	//----------------------------------
	
	/**
	 * @copy org.teotigraphix.swizplugin.registry.IExtensionDescriptor#extension
	 */
	public function get extension():IExtension
	{
		var result:Object = this;
		
		while(result != null)
		{
			if (!("parent" in result))
				break;
			
			result = result.parent;
		}
		
		return result as IExtension;
	}
	
	//----------------------------------
	//  parent
	//----------------------------------
	
	/**
	 * @copy org.teotigraphix.swizplugin.registry.IExtensionDescriptor#parent
	 */
	public function get parent():Object
	{
		var parent:Object = registry.getRegistryExtension(parentID);
		
		if (parent) 
			return parent;
		
		return registry.getRegistryExtensionDescriptor(parentID);
	}
	
	//----------------------------------
	//  id
	//----------------------------------
	
	/**
	 * Returns the <code>id</code> attribute found in the <code>properties</code>,
	 * <code>null</code> if the <code>properties</code> or <code>id</code>
	 * does not exist.
	 */
	public function get uid():String
	{
		return getAttribute("uid");
	}
	
	//----------------------------------
	//  options
	//----------------------------------
	
	/**
	 * @copy org.teotigraphix.swizplugin.registry.IExtensionDescriptor#options
	 */
	public function get options():Object
	{
		return _properties;
	}
	
	//--------------------------------------------------------------------------
	//
	//  Constructor
	//
	//--------------------------------------------------------------------------
	
	/**
	 * @private
	 */
	public function RegistryExtensionDescriptor(registry:ExtensionRegistry, 
												registryID:int, 
												children:Array = null)
	{
		super(registry, registryID);
		
		children = children;
	}
	
	//--------------------------------------------------------------------------
	//
	//  IExtensionDescriptor API :: Methods
	//
	//--------------------------------------------------------------------------
	
	/**
	 * @copy org.teotigraphix.swizplugin.registry.IExtensionDescriptor#createExecutableExtension()
	 */
	public function createExecutableExtension(propertyName:String,
											  responder:IResponder = null):ExecutableRequest
	{
		if (_properties == null)
			return null;
		
		var className:Object = _properties[propertyName];
		if (className == null)
			return null;
		
		if (className is Class) // this was from an Extension descriptor, not XML
		{
			// get the string class name, so we don't duplicate creation logic
			var tempName:String = getQualifiedClassName(className);
			if (tempName.indexOf("::") != -1)
				tempName = tempName.replace("::", ".");
			
			className = tempName;
		}
		
		// the plugin that contributed this descriptor
		var contributor:IContributor = registry.getContributor(_contributorID);
		
		// ask the extension reg for the token
		var token:ExecutableRequest = registry.createExecutableExtension( 
			contributor, className.toString()) as ExecutableRequest;
		
		token.descriptor = this;
		
		if (responder != null)
			token.addResponder(responder);
		
		return token;
	}
	
	/**
	 * @copy org.teotigraphix.swizplugin.registry.IExtensionDescriptor#getAttribute()
	 */
	public function getAttribute(name:String):*
	{
		if (_properties == null || !_properties.hasOwnProperty(name))
			return null;
		
		return _properties[name];
	}
	
	/**
	 * @copy org.teotigraphix.swizplugin.registry.IExtensionDescriptor#getAttributeNames()
	 */
	public function getAttributeNames():Array
	{
		var result:Array = [];
		var name:String;
		
		if (_properties is XML)
		{
			for each (name in _properties) 
			{
				result.push(name);
			}
		}
		else if (_properties is PluginOptions)
		{
			for each (name in PluginOptions(_properties).listEnumerations()) 
			{
				result.push(name);
			}
		}
		
		return result;
	}
	
	/**
	 * @copy org.teotigraphix.swizplugin.registry.IExtensionDescriptor#hasAttribute()
	 */
	public function hasAttribute(propertyName:String):Boolean
	{
		if (_properties == null)
			return false;
		
		if (!(propertyName in _properties))
			return false;
		
		if ((_properties[propertyName] is Number)
			&& isNaN(_properties[propertyName]))
			return false;
		
		if (_properties[propertyName] == null)
			return false;
		
		return true;
	}
	
	/**
	 * @copy org.teotigraphix.swizplugin.registry.IExtensionDescriptor#getChild()
	 */
	public function getChild(name:String):IExtensionDescriptor
	{
		if (children == null || children.length == 0)
			return null;
		
		var child:IExtensionDescriptor = registry.
			getRegistryExtensionDescriptor(children[0]) as IExtensionDescriptor;
		
		if (child != null && child.name == name)
			return child;
		
		return null;
	}
	
	/**
	 * @copy org.teotigraphix.swizplugin.registry.IExtensionDescriptor#getChildren()
	 */
	public function getChildren(name:String = null):Array
	{
		var result:Array = [];
		if (children == null)
			return result;
		
		for (var i:int = 0; i < children.length; i++) 
		{
			var child:IExtensionDescriptor = 
				registry.getRegistryExtensionDescriptor(children[i]);
			
			if (name == null || child.name == name) 
			{
				result.push(child);
			}
		}
		
		return result;
	}
	
	/**
	 * @copy org.teotigraphix.swizplugin.registry.IExtensionDescriptor#getValue()
	 */
	public function getValue():String
	{
		var text:String = getAttribute("text");
		if (text != null)
			return text;
		
		// TODO implement XML
		return null;
	}
}
}